package com.cloudeye.logtest.basic;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * 乐观锁：认为自己可以操作成功，当有多个线程访问一个变量时，只有一个线程可以获锁成功，其他线程不会阻塞，二是立即返回，然后再次尝试获得锁
 */

/**
 *   cunt++的逻辑：1.执行线程从本地工作内存中获取count，如果没有获取，则从主内存获取，然后放到本地工作内存；2对本地工作内存的count进行+1
 *  3.将+1后的值放到主内存。一个变量的读取和复制是原子的，但是赋值给另外一个变量不是原子的（第三步）。
 */

/**
 * cas compare and swap . 只有当期望值等于内存中取出的值，才给内存变量赋值，并返回true.否则返回false
 */
public class CASTest {

    volatile static int count = 0;

    public synchronized static void request0() throws InterruptedException {
//        TimeUnit.MICROSECONDS.sleep(10);
        Thread.sleep(10);
        count++;
    }

    public static void request() throws InterruptedException {
//        TimeUnit.MICROSECONDS.sleep(10);
        Thread.sleep(10);
        int expectCount  ;
        while (!compareAndSwap((expectCount=getCount()) , expectCount + 1)) {
        }
    }

    public static void run() throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(100);
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                try {
                    request();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    latch.countDown();
                }
            }).start();
        }
        latch.await();
        long end = System.currentTimeMillis();
        System.out.println("count：" + count + ",耗时：" + (end - start));
    }

    public static void run0() throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(100);
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                try {
                    request0();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    latch.countDown();
                }
            }).start();
        }
        latch.await();
        long end = System.currentTimeMillis();
        System.out.println("count：" + count + ",耗时：" + (end - start));
    }

    public static synchronized  boolean compareAndSwap(int expectedCount, int newCount) {
        if (getCount() == expectedCount) {
            count = newCount;
            return true;
        } else {
            return false;
        }
    }

    public static int getCount() {
        return count;
    }

    public static void main(String[] args) throws InterruptedException {
        run0();
        run();
    }
}
